package org.groupg.project.handler;


import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import org.apache.commons.lang3.StringUtils;
import org.groupg.project.config.RuleConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class ProxyFrontendHandler extends ChannelInboundHandlerAdapter {
    private static final Logger log = LoggerFactory.getLogger(ProxyFrontendHandler.class);
    private final List<RuleConfig> rules;
    private Channel outboundChannel;

    public ProxyFrontendHandler(List<RuleConfig> rules) {
        // 按order排序，order小的优先匹配
        this.rules = rules.stream()
                .sorted(Comparator.comparingInt(RuleConfig::getOrder))
                .collect(Collectors.toList());
    }

    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            String uri = request.uri();

            // 查找匹配的规则
            RuleConfig matchedRule = findMatchedRule(uri);
            if (matchedRule == null) {
                sendErrorResponse(ctx, HttpResponseStatus.BAD_GATEWAY, "没找到匹配的链接: " + uri);
                return;
            }

            // 重写URI
            String newUri = rewriteUri(uri, matchedRule);
            request.setUri(newUri);

            // 建立到目标服务器的连接
            Bootstrap b = new Bootstrap();
            b.group(ctx.channel().eventLoop())
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) {
                            ChannelPipeline p = ch.pipeline();
                            if (matchedRule.isSsl()) {
                                // TODO 添加SSL处理（如果需要）
                                System.out.println("暂不支持SSL");
                            }
                            p.addLast(new HttpClientCodec());
                            p.addLast(new HttpObjectAggregator(65536));
                            p.addLast(new ProxyBackendHandler(ctx.channel()));
                        }
                    });

            ChannelFuture f = b.connect(matchedRule.getTargetHost(), matchedRule.getTargetPort());
            outboundChannel = f.channel();

            f.addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {
                    outboundChannel.writeAndFlush(msg);
                } else {
                    ctx.channel().close();
                }
            });
        }
    }

    private RuleConfig findMatchedRule(String uri) {
        for (RuleConfig rule : rules) {
            Pattern pattern = Pattern.compile(rule.getMatchPattern());
            if (pattern.matcher(uri).matches()) {
                return rule;
            }
        }
        return null;
    }

    private String rewriteUri(String originalUri, RuleConfig rule) throws URISyntaxException {
        URI uri = new URI(originalUri);
        String path = uri.getPath();

        // 应用重写规则
        if (StringUtils.isNotBlank(rule.getRewritePattern())) {
            Pattern pattern = Pattern.compile(rule.getMatchPattern());
            Matcher matcher = pattern.matcher(path);
            log.debug("{} 替换为：{}", path, matcher);
            if (matcher.matches()) {
                path = path.replaceAll(rule.getMatchPattern(), rule.getRewritePattern());
            }
        }

        return new URI(
                rule.isSsl() ? "https" : "http",
                null,
                rule.getTargetHost(),
                rule.getTargetPort(),
                path,
                uri.getQuery(),
                uri.getFragment()
        ).toString();
    }

    private void sendErrorResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String message) {
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                status,
                Unpooled.copiedBuffer(message.getBytes()));
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error(cause.getMessage(), cause);
        if (ctx.channel().isActive()) {
            sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, cause.getMessage());
        }
    }


}
